package com.linkwings.dbTemp;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class DbUtils {

	public static List resultSetToListMap(ResultSet resultSet) throws SQLException{
		List<Map<String,Object>> list =new ArrayList<Map<String,Object>>();
		if(resultSet!=null){
			ResultSetMetaData md = resultSet.getMetaData();
			int columnCount = md.getColumnCount();
			Map<String,Object> dataMap=null;
			while (resultSet.next()){
				dataMap = new HashMap<String,Object>(columnCount);
				for (int i=1; i<=columnCount; i++){
					dataMap.put(md.getColumnName(i),resultSet.getObject(i));
				}
				list.add(dataMap);
			}

		}
		return list;
	}



	public static List resultSetToListObject(ResultSet resultSet,Class cla) throws Exception{
		List<Object> list=new ArrayList<Object>();
		if(resultSet!=null){
			ResultSetMetaData md = resultSet.getMetaData();
			int columnCount = md.getColumnCount();
			Class clazzT = cla;
			Map<String,Method> methodMap=getSetterMethodsLowerCasePropertyNameMap(clazzT);
			Object obj=null;
			while (resultSet.next()){
				obj=clazzT.newInstance();
				for (int i=1; i<=columnCount; i++){
					String formatLowerCaseColumnName=getFormatLowerCaseColumnName(md.getColumnName(i));
					if(formatLowerCaseColumnName!=null){
						Method m=methodMap.get(formatLowerCaseColumnName);
						if(m!=null){
							try{
							 invokeResultToMethod(m,obj,resultSet,i);
							//m.invoke(obj, new Object[]{resultSet.getObject(i)});
							}catch(Exception r){
								System.err.println("Invoke value to class error: Method ["+m.getName()+"] .");
								r.printStackTrace();
								return null;
							}

						}
					}
				}
				list.add(obj);
			}


		}
		return list;
	}

	public static List resultSetToListObject(ResultSet resultSet,Class cla,Map<String,String> columnNameMap) throws Exception{
		List<Object> list=new ArrayList<Object>();

		if(resultSet!=null){
			Map<String,String> propertyColumnNameMap=columnNameMap;
			Class clazzT = cla;
			Object obj=null;
			while (resultSet.next()){
				Set<String> keyset=propertyColumnNameMap.keySet();
				obj=clazzT.newInstance();
				String columName=null;
				String setterMethodName=null;
				String getterMethodName=null;
				for(String propertyName : keyset){
					if(propertyColumnNameMap.get(propertyName)!=null){
						setterMethodName=ClassUtils.getSetterMethodName(propertyName);
						getterMethodName=ClassUtils.getGetterMethodName(propertyName);
						columName=propertyColumnNameMap.get(propertyName);
							Method gm=cla.getMethod(getterMethodName, null);
							if(gm!=null&&gm.getReturnType()!=null&&gm.getReturnType().toString().equals("void")==false){
								Method sm=cla.getMethod(setterMethodName, new Class[]{gm.getReturnType()});
								if(sm!=null){
									try{
									invokeResultToMethod(sm,obj,resultSet,columName);
									//sm.invoke(obj, resultSet.getObject(columName));
								}catch(Exception r){
									System.err.println("Invoke value to class error: Method ["+sm.getName()+"] Type ["+sm.getTypeParameters()[0].toString()+"].");
									r.printStackTrace();
									return null;
								}
								}
							}
					}

				}
				list.add(obj);
			}

		}
		return list;
	}

	public static List resultSetToListMapperObject(ResultSet resultSet,Class cla) throws Exception{
		Field mapField = cla.getField("DB_AUTO_MAP");
		if(mapField!=null){
			if(mapField.getType().equals(Map.class)){

				Map columnNameMap = null;
				try{
				columnNameMap = (Map)mapField.get(null);
				}catch(Exception r){
					System.err.println("Mapper Object Class Error: Class ["+cla.getCanonicalName()+"] no public static Map for fields .");
					return null;
				}
				return resultSetToListObject(resultSet,cla,columnNameMap);
			}

		}
		return null;
	}

	public static List resultSetToListMapperObject(ResultSet resultSet,Class cla,String mapperFieldName) throws Exception{
		Field mapField = cla.getField(mapperFieldName);
		if(mapField!=null){
			if(mapField.getType().equals(Map.class)){
				Map columnNameMap = null;
				try{
					columnNameMap = (Map)mapField.get(null);
					}catch(Exception r){
						System.err.println("Mapper Object Class Error: Class ["+cla.getCanonicalName()+"] no public static Map for fields .");
						return null;
					}
				return resultSetToListObject(resultSet,cla,columnNameMap);
			}

		}
		return null;
	}

	private static Map<String,Method> getSetterMethodsLowerCasePropertyNameMap(Class cla) throws Exception{
		Method[] methods=cla.getMethods();
		Map<String,Method> map=new HashMap<String,Method>();
		Method method=null;
		for(int i=0;i<methods.length;i++){
			String setMathodName=methods[i].getName();
			if(setMathodName!=null&&setMathodName.startsWith("set")) {
				method=methods[i];
				Type[] types=method.getGenericParameterTypes();
				String propertyName=ClassUtils.getPropertyName(setMathodName);
				if(propertyName!=null&&types.length==1){
				  map.put(propertyName.toLowerCase(), method);
				}
			}
		}
		return map;
	}


	public static String getFormatLowerCaseColumnName(String columnName){
		if(columnName==null){
			return null;
		}
		String str=columnName;
		str=str.replaceAll("_", "");
		str=str.replaceAll(" ", "");
		str=str.trim().toLowerCase();
		return str;
	}



	private static void  invokeResultToMethod(Method m,Object obj,ResultSet resultSet,String columName) throws Exception{
		Method method=m;
		Class[] classTypes=method.getParameterTypes();
		Class classType=classTypes[0];

		if(classType==Array.class){
			m.invoke(obj, resultSet.getArray(columName));
		}else if(classType==Blob.class){
			m.invoke(obj, resultSet.getBlob(columName));
		}else if(classType==Boolean.class){
			m.invoke(obj, resultSet.getBoolean(columName));
		}else if(classType==Byte.class){
			m.invoke(obj, resultSet.getBytes(columName));
		}else if(classType==Float.class){
			m.invoke(obj, resultSet.getFloat(columName));
		}else if(classType==Clob.class){
			m.invoke(obj, resultSet.getClob(columName));
		}else if(classType==Double.class){
			m.invoke(obj, resultSet.getDouble(columName));
		}else if(classType==Integer.class){
			m.invoke(obj, resultSet.getInt(columName));
		}else if(classType==Long.class){
			m.invoke(obj, resultSet.getLong(columName));
		}else if(classType==Ref.class){
			m.invoke(obj, resultSet.getRef(columName));
		}else if(classType==Short.class){
			m.invoke(obj, resultSet.getShort(columName));
		}else{
			m.invoke(obj, resultSet.getObject(columName));
		}
	}
	private static void  invokeResultToMethod(Method m,Object obj,ResultSet resultSet,int index)throws Exception{
		Method method=m;
		Class[] classTypes=method.getParameterTypes();
		Class classType=classTypes[0];

		if(classType==Array.class){
			m.invoke(obj, resultSet.getArray(index));
		}else if(classType==Blob.class){
			m.invoke(obj, resultSet.getBlob(index));
		}else if(classType==Boolean.class){
			m.invoke(obj, resultSet.getBoolean(index));
		}else if(classType==Byte.class){
			m.invoke(obj, resultSet.getBytes(index));
		}else if(classType==Float.class){
			m.invoke(obj, resultSet.getFloat(index));
		}else if(classType==Clob.class){
			m.invoke(obj, resultSet.getClob(index));
		}else if(classType==Double.class){
			m.invoke(obj, resultSet.getDouble(index));
		}else if(classType==Integer.class){
			m.invoke(obj, resultSet.getInt(index));
		}else if(classType==Long.class){
			m.invoke(obj, resultSet.getLong(index));
		}else if(classType==Ref.class){
			m.invoke(obj, resultSet.getRef(index));
		}else if(classType==Short.class){
			m.invoke(obj, resultSet.getShort(index));
		}else{
			m.invoke(obj, resultSet.getObject(index));
		}
	}



}
